#include "configmanager.h"

#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QDebug>
#include <QSettings>
#include <QMutexLocker>

// static init
ConfigManager* ConfigManager::m_instance = nullptr;
QMutex ConfigManager::m_mutex;

ConfigManager::ConfigManager(QObject *parent) : QObject(parent) {
	// 条件编译下的不同配置文件路径
	#ifdef Q_OS_WIN
		QFileInfo cppFileInfo(__FILE__);  // 获取当前configmanager.cpp的文件信息
    	QDir settingsDir = cppFileInfo.dir();  // 进入cpp文件所在目录（即settings目录）
    	m_configPath = settingsDir.filePath("config.ini");  // 拼接config.ini路径
	#else
		// 其他操作系统下同样使用相对路径（结构相同）
        QDir currentDir(QFileInfo(__FILE__).absolutePath());
        m_configPath = currentDir.filePath("config.ini");
	#endif

	// 确保配置目录存在（若settings目录被删除，自动创建）
    QFileInfo configFileInfo(m_configPath);
    QDir parentDir = configFileInfo.dir();
    if (!parentDir.exists()) {
        if (!parentDir.mkpath(".")) {  // 创建多级目录（如settings不存在时）
            qWarning() << "[ConfigManager] 无法创建配置目录：" << parentDir.absolutePath();
        }
    }

	// init config 
	m_settings = new QSettings(m_configPath, QSettings::IniFormat, this);
	// 设置ini编码为UTF-8，支持中文配置项（如皮肤名称、快捷键）
    #if QT_VERSION_MAJOR < 6
        m_settings->setIniCodec("UTF-8");  // Qt 5中显式设置UTF-8编码
    #endif

	// load  fault 则 default
	if (!loadConfig()) {
        qInfo() << "[ConfigManager] 配置文件加载失败，使用默认配置：" << m_configPath;
        initDefaultConfig();
    } else {
        qInfo() << "[ConfigManager] 配置文件加载成功：" << m_configPath;
    }

    // 绑定单例生命周期到应用程序，确保程序退出时自动析构
    connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
        saveConfig();  // 退出前强制保存配置
        delete m_instance;
        m_instance = nullptr;
    });
}

ConfigManager::~ConfigManager()
{
	// 析构之后要save 然后立刻执行
	// saveConfig();	// 里面有执行函数
	// 先保存配置，再释放QSettings资源
	if (saveConfig())	qInfo() << "[ConfigManager] 配置已保存到：" << m_configPath;
	else				qWarning() << "[ConfigManager] 配置保存失败：" << m_configPath;

	delete m_settings;  // 释放QSettings实例，避免内存泄漏
    m_settings = nullptr;
}

ConfigManager *ConfigManager::getInstance(QObject *parent)
{
	// 双锁 check 线程safe
	if (!m_instance) {
		QMutexLocker locker(&m_mutex);
		if (!m_instance)	m_instance = new ConfigManager(parent);
	}
	return m_instance;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// getter and setter
InputMethodConfig::Data ConfigManager::getInputMethodConfig() const
{
	QMutexLocker locker(&m_mutex);
    // 从m_configData中获取结构化数据（若不存在则返回默认值）
    if (m_configData.contains(InputMethodGroup)) {
        return m_configData[InputMethodGroup].value<InputMethodConfig::Data>();
    }
    // 兜底：返回configdef.h中的默认配置
    InputMethodConfig::Data defaultConfig;
    return defaultConfig;
}

void ConfigManager::setInputMethodConfig(const InputMethodConfig::Data &config)
{
	QMutexLocker locker(&m_mutex);
    // 对比新旧配置，仅变更时更新并发送信号
    InputMethodConfig::Data oldConfig = getInputMethodConfig();
	bool isConfigChanged = false;

	// 对比双拼方案：变更则触发信号
	if (oldConfig.doublePinyinScheme != config.doublePinyinScheme) {
		emit doublePinyinSchemeChanged(config.doublePinyinScheme);
        qInfo() << "[ConfigManager] 双拼方案更新：" << oldConfig.doublePinyinScheme << "→" << config.doublePinyinScheme;
        isConfigChanged = true;
	}
	// 对比模糊音开关：变更则触发信号
	if (oldConfig.fuzzyPinyin != config.fuzzyPinyin) {
        emit fuzzyPinyinChanged(config.fuzzyPinyin);
        qInfo() << "[ConfigManager] 模糊音状态更新：" << oldConfig.fuzzyPinyin << "→" << config.fuzzyPinyin;
        isConfigChanged = true;
    }
	// 对比候选词数量：变更则触发信号
	if (oldConfig.candidateCount != config.candidateCount) {
        emit candidateCountChanged(config.candidateCount);
        qInfo() << "[ConfigManager] 候选词数量更新：" << oldConfig.candidateCount << "→" << config.candidateCount;
        isConfigChanged = true;
    }
    // 检查OpenCC路径和百度API密钥变更
    if (oldConfig.openccDicPath != config.openccDicPath ||
        oldConfig.baiduApiAppId != config.baiduApiAppId ||
        oldConfig.baiduApiSecretKey != config.baiduApiSecretKey) {
        isConfigChanged = true;
    }
    if (oldConfig.baseDictPath != config.baseDictPath ||
        oldConfig.mysqlHost != config.mysqlHost ||
        oldConfig.userWordEncrypt != config.userWordEncrypt) {
        isConfigChanged = true;
    }

    if (isConfigChanged) {
        m_configData[InputMethodGroup] = QVariant::fromValue(config);
        emit inputMethodConfigChanged(config);
        qInfo() << "[ConfigManager] 输入法配置已更新：双拼方案=" << config.doublePinyinScheme 
                << "，OpenCC路径=" << config.openccDicPath;
    }
}

GeneralConfig::Data ConfigManager::getGeneralConfig() const
{
	QMutexLocker locker(&m_mutex);
    if (m_configData.contains(GeneralGroup)) {
        return m_configData[GeneralGroup].value<GeneralConfig::Data>();
    }
    GeneralConfig::Data defaultConfig;
    return defaultConfig;
}

void ConfigManager::setGeneralConfig(const GeneralConfig::Data &config)
{
	QMutexLocker locker(&m_mutex);
    GeneralConfig::Data oldConfig = getGeneralConfig();
    if (oldConfig.language != config.language || oldConfig.autoStart != config.autoStart) {
        m_configData[GeneralGroup] = QVariant::fromValue(config);
        emit generalConfigChanged(config);
        qInfo() << "[ConfigManager] 通用配置已更新：语言=" << config.language 
                << "，开机自启=" << config.autoStart;
    }
}

AppearanceConfig::Data ConfigManager::getAppearanceConfig() const
{
	QMutexLocker locker(&m_mutex);
    if (m_configData.contains(AppearanceGroup)) {
        return m_configData[AppearanceGroup].value<AppearanceConfig::Data>();
    }
    AppearanceConfig::Data defaultConfig;
    return defaultConfig;
}

void ConfigManager::setAppearanceConfig(const AppearanceConfig::Data &config)
{
	QMutexLocker locker(&m_mutex);
    AppearanceConfig::Data oldConfig = getAppearanceConfig();
    if (oldConfig.skin != config.skin || oldConfig.fontSize != config.fontSize) {
        m_configData[AppearanceGroup] = QVariant::fromValue(config);
        emit appearanceConfigChanged(config);
        qInfo() << "[ConfigManager] 外观配置已更新：皮肤=" << config.skin 
                << "，字体大小=" << config.fontSize;
    }
}

ShortcutConfig::Data ConfigManager::getShortcutConfig() const
{
	QMutexLocker locker(&m_mutex);
    if (m_configData.contains(ShortcutGroup)) {
        return m_configData[ShortcutGroup].value<ShortcutConfig::Data>();
    }
    ShortcutConfig::Data defaultConfig;
    return defaultConfig;
}

void ConfigManager::setShortcutConfig(const ShortcutConfig::Data &config)
{
	QMutexLocker locker(&m_mutex);
    ShortcutConfig::Data oldConfig = getShortcutConfig();
    if (oldConfig.switchLanguage != config.switchLanguage) {
        m_configData[ShortcutGroup] = QVariant::fromValue(config);
        emit shortcutConfigChanged(config);
        qInfo() << "[ConfigManager] 快捷键配置已更新：中英文切换=" << config.switchLanguage;
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////

// QVariant ConfigManager::getValue(ConfigGroup group, const QString &key, const QVariant &defaultValue)
// {
// 	QMutexLocker locker(&m_mutex);
// 	// 获取比对一下
// 	if (m_configData[group].contains(key))	return m_configData[group][key];

// 	// 否则就default
// 	setValue(group, key, defaultValue);
// 	return defaultValue;
// }

// void ConfigManager::setValue(ConfigGroup group, const QString &key, const QVariant &value)
// {
// 	QMutexLocker locker(&m_mutex);

// 	// map的插入
// 	if (m_configData[group].value(key) != value) {
// 		m_configData[group][key] = value;
//         emit configChanged(group, key, value);
// 	}
// }

bool ConfigManager::saveConfig()
{
	QMutexLocker locker(&m_mutex);
	if (!m_settings) {
        qWarning() << "[ConfigManager] QSettings实例未初始化，保存失败";
        return false;
    }

	// 保存输入法配置（对应ini中的[InputMethod]分组）
    InputMethodConfig::Data imConfig = getInputMethodConfig();
    m_settings->beginGroup(groupToString(InputMethodGroup));

    m_settings->setValue("DoublePinyinScheme", imConfig.doublePinyinScheme);
    m_settings->setValue("BaseDictPath", imConfig.baseDictPath);
    m_settings->setValue("BaseDictEncrypted", imConfig.baseDictEncrypted);
    m_settings->setValue("AutoAddWord", imConfig.autoAddWord);
    m_settings->setValue("AutoAddThreshold", imConfig.autoAddThreshold);
    m_settings->setValue("CandidateCount", imConfig.candidateCount);
    m_settings->setValue("FuzzyPinyin", imConfig.fuzzyPinyin);
    // MySQL配置项
    m_settings->setValue("MySQLDbName", imConfig.mysqlDbName);
    m_settings->setValue("MySQLHost", imConfig.mysqlHost);
    m_settings->setValue("MySQLPassword", imConfig.mysqlPassword);
    m_settings->setValue("MySQLPort", imConfig.mysqlPort);
    m_settings->setValue("MySQLUser", imConfig.mysqlUser);
    m_settings->setValue("MySQLTable", imConfig.mysqlTable);
    m_settings->setValue("UserWordEncrypt", imConfig.userWordEncrypt);
    // opencc | baiduAPI
    m_settings->setValue("OpenCCDictPath", imConfig.openccDicPath);
    m_settings->setValue("BaiduApi_AppId", imConfig.baiduApiAppId);
    m_settings->setValue("BaiduApi_SecretKey", imConfig.baiduApiSecretKey);
    m_settings->endGroup();

    // 保存通用配置（对应ini中的[General]分组）
    GeneralConfig::Data generalConfig = getGeneralConfig();
    m_settings->beginGroup(groupToString(GeneralGroup));
    m_settings->setValue("Language", generalConfig.language);
    m_settings->setValue("AutoStart", generalConfig.autoStart);
    m_settings->setValue("ShowTrayIcon", generalConfig.showTrayIcon);
    m_settings->endGroup();

    // 保存外观配置（对应ini中的[Appearance]分组）
    AppearanceConfig::Data appearanceConfig = getAppearanceConfig();
    m_settings->beginGroup(groupToString(AppearanceGroup));
    m_settings->setValue("Skin", appearanceConfig.skin);
    m_settings->setValue("FontSize", appearanceConfig.fontSize);
    m_settings->setValue("WindowTransparency", appearanceConfig.windowTransparency);
    m_settings->endGroup();

    // 保存快捷键配置（对应ini中的[Shortcut]分组）
    ShortcutConfig::Data shortcutConfig = getShortcutConfig();
    m_settings->beginGroup(groupToString(ShortcutGroup));
    m_settings->setValue("SwitchLanguage", shortcutConfig.switchLanguage);
    m_settings->setValue("SwitchSimplifiedTraditional", shortcutConfig.switchSimplifiedTraditional);
    m_settings->setValue("ShowNumpad", shortcutConfig.showNumpad);
    m_settings->endGroup();

    // 强制写入磁盘（避免QSettings缓存导致数据丢失）
    m_settings->sync();
    // 检查保存状态
    if (m_settings->status() != QSettings::NoError) {
        qWarning() << "[ConfigManager] 配置保存失败，错误码：" << m_settings->status();
        return false;
    }
    return true;
}

bool ConfigManager::loadConfig()
{
	QMutexLocker locker(&m_mutex);
	// 首先配置文件要存在才能读取加载
	if (!QFile::exists(m_configPath)) {
        qWarning() << "[ConfigManager] 配置文件不存在：" << m_configPath;
        return false;
    }
	if (!m_settings) {
        qWarning() << "[ConfigManager] QSettings实例未初始化，加载失败";
        return false;
    }

	// 先获取默认结构化配置，再用ini值覆盖（确保缺失项不丢失）
    InputMethodConfig::Data imConfig;  // 初始为configdef.h的默认值
    // 加载[InputMethod]分组配置
    m_settings->beginGroup(groupToString(InputMethodGroup));
    imConfig.doublePinyinScheme = m_settings->value("DoublePinyinScheme", imConfig.doublePinyinScheme).toString();
    imConfig.baseDictPath = m_settings->value("BaseDictPath", imConfig.baseDictPath).toString();
    imConfig.baseDictEncrypted = m_settings->value("BaseDictEncrypted", imConfig.baseDictEncrypted).toBool();
    imConfig.autoAddWord = m_settings->value("AutoAddWord", imConfig.autoAddWord).toBool();
    imConfig.autoAddThreshold = m_settings->value("AutoAddThreshold", imConfig.autoAddThreshold).toInt();
    imConfig.candidateCount = m_settings->value("CandidateCount", imConfig.candidateCount).toInt();
    imConfig.fuzzyPinyin = m_settings->value("FuzzyPinyin", imConfig.fuzzyPinyin).toBool();
    // MySQL配置项
    imConfig.mysqlDbName = m_settings->value("MySQLDbName", imConfig.mysqlDbName).toString();
    imConfig.mysqlHost = m_settings->value("MySQLHost", imConfig.mysqlHost).toString();
    imConfig.mysqlPassword = m_settings->value("MySQLPassword", imConfig.mysqlPassword).toString();
    imConfig.mysqlPort = m_settings->value("MySQLPort", imConfig.mysqlPort).toInt();
    imConfig.mysqlUser = m_settings->value("MySQLUser", imConfig.mysqlUser).toString();
    imConfig.mysqlTable = m_settings->value("MySQLTable", imConfig.mysqlTable).toString();
    imConfig.userWordEncrypt = m_settings->value("UserWordEncrypt", imConfig.userWordEncrypt).toBool();
    ////////////////////////////////////////////
    imConfig.openccDicPath = m_settings->value("OpenCCDictPath", imConfig.openccDicPath).toString();
    imConfig.baiduApiAppId = m_settings->value("BaiduApi_AppId", imConfig.baiduApiAppId).toString();
    imConfig.baiduApiSecretKey = m_settings->value("BaiduApi_SecretKey", imConfig.baiduApiSecretKey).toString();
    ////////////////////////////////////////////
    m_settings->endGroup();
    // 保存到m_configData
    m_configData[InputMethodGroup] = QVariant::fromValue(imConfig);

    // 加载通用配置（逻辑同上）
    GeneralConfig::Data generalConfig;
    m_settings->beginGroup(groupToString(GeneralGroup));
    generalConfig.language = m_settings->value("Language", generalConfig.language).toString();
    generalConfig.autoStart = m_settings->value("AutoStart", generalConfig.autoStart).toBool();
    generalConfig.showTrayIcon = m_settings->value("ShowTrayIcon", generalConfig.showTrayIcon).toBool();
    m_settings->endGroup();
    m_configData[GeneralGroup] = QVariant::fromValue(generalConfig);

    // 加载外观配置（逻辑同上）
    AppearanceConfig::Data appearanceConfig;
    m_settings->beginGroup(groupToString(AppearanceGroup));
    appearanceConfig.skin = m_settings->value("Skin", appearanceConfig.skin).toString();
    appearanceConfig.fontSize = m_settings->value("FontSize", appearanceConfig.fontSize).toInt();
    appearanceConfig.windowTransparency = m_settings->value("WindowTransparency", appearanceConfig.windowTransparency).toInt();
    m_settings->endGroup();
    m_configData[AppearanceGroup] = QVariant::fromValue(appearanceConfig);

    // 加载快捷键配置（逻辑同上）
    ShortcutConfig::Data shortcutConfig;
    m_settings->beginGroup(groupToString(ShortcutGroup));
    shortcutConfig.switchLanguage = m_settings->value("SwitchLanguage", shortcutConfig.switchLanguage).toString();
    shortcutConfig.switchSimplifiedTraditional = m_settings->value("SwitchSimplifiedTraditional", shortcutConfig.switchSimplifiedTraditional).toString();
    shortcutConfig.showNumpad = m_settings->value("ShowNumpad", shortcutConfig.showNumpad).toString();
    m_settings->endGroup();
    m_configData[ShortcutGroup] = QVariant::fromValue(shortcutConfig);

    return true;
}

void ConfigManager::restoreDefaults()
{
	QMutexLocker locker(&m_mutex);
	m_configData.clear();			// 清空现有配置
	
	// 直接使用configdef.h的默认结构体初始化
    m_configData[InputMethodGroup] = QVariant::fromValue(InputMethodConfig::Data());
    m_configData[GeneralGroup] = QVariant::fromValue(GeneralConfig::Data());
    m_configData[AppearanceGroup] = QVariant::fromValue(AppearanceConfig::Data());
    m_configData[ShortcutGroup] = QVariant::fromValue(ShortcutConfig::Data());

    qInfo() << "[ConfigManager] 已恢复所有默认配置";
    // 发送全部分组的变更信号
    emit inputMethodConfigChanged(getInputMethodConfig());
    emit generalConfigChanged(getGeneralConfig());
    emit appearanceConfigChanged(getAppearanceConfig());
    emit shortcutConfigChanged(getShortcutConfig());
}

QString ConfigManager::getConfigFilePath() const
{
	return m_configPath;
}

void ConfigManager::initDefaultConfig()
{
	// 完全基于configdef.h的默认值，避免重复硬编码
    m_configData[InputMethodGroup] = QVariant::fromValue(InputMethodConfig::Data());
    m_configData[GeneralGroup] = QVariant::fromValue(GeneralConfig::Data());
    m_configData[AppearanceGroup] = QVariant::fromValue(AppearanceConfig::Data());
    m_configData[ShortcutGroup] = QVariant::fromValue(ShortcutConfig::Data());

    qInfo() << "[ConfigManager] 默认配置初始化完成";
}

QString ConfigManager::groupToString(ConfigGroup group) const
{
	switch (group) {
    case GeneralGroup:
        return "General";
    case InputMethodGroup:
        return "InputMethod";
    case AppearanceGroup:
        return "Appearance";
    case ShortcutGroup:
        return "Shortcut";
    default:
        qWarning() << "[ConfigManager] 未知配置分组，默认使用General";
        return "General";
    }
}

void ConfigManager::setOpenCCDictPath(const QString &path)
{
    QMutexLocker locker(&m_mutex);
    InputMethodConfig::Data config = getInputMethodConfig();
    if (config.openccDicPath != path) {
        config.openccDicPath = path;
        setInputMethodConfig(config);
        qInfo() << "[ConfigManager] OpenCC词典路径更新为：" << path;
    }
}

void ConfigManager::setBaiduApiConfig(const QString &encryptedAppId, const QString &encryptedSecretKey)
{
    QMutexLocker locker(&m_mutex);
    InputMethodConfig::Data config = getInputMethodConfig();
    bool changed = false;
    if (config.baiduApiAppId != encryptedAppId) {
        config.baiduApiAppId = encryptedAppId;
        changed = true;
    }
    if (config.baiduApiSecretKey != encryptedSecretKey) {
        config.baiduApiSecretKey = encryptedSecretKey;
        changed = true;
    }
    if (changed) {
        setInputMethodConfig(config);
        qInfo() << "[ConfigManager] 百度API密钥配置已更新";
    }
}
